import hashlib
import time
import threading
import logging
from datetime import datetime, timedelta
from flask import request, jsonify
from wxcloudrun.dao import delete_counterbyid, query_counterbyid, insert_counter, update_counterbyid
from wxcloudrun.model import Counters
from wxcloudrun.response import make_succ_empty_response, make_succ_response, make_err_response
from flask_cors import CORS
from .stock_financial_analyzer import StockFinancialAnalyzer
from .stock_technical_analyzer import StockTechnicalAnalyzer
from .func import fetch_stock_info
from run import app
import os
import akshare as ak
import pandas as pd
import csv
import pymysql
import json

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger('StockAnalyzer')

# 从环境变量获取数据库配置
DB_HOST = os.getenv('DB_HOST', '10.4.110.125')
DB_PORT = int(os.getenv('DB_PORT', 3306))
DB_USER = os.getenv('DB_USER', 'xiaodoubao')
DB_PASSWORD = os.getenv('DB_PASSWORD', 'Ddx198871')
DB_NAME = os.getenv('DB_NAME', 'xdb_ai')

# 全局分析器实例（线程安全）
analyzer_lock = threading.Lock()
financial_analyzer = None
technical_analyzer = None

# 任务缓存（存储正在处理的任务）
financial_task_cache = {}
technical_task_cache = {}
# 任务缓存锁
financial_cache_lock = threading.Lock()
technical_cache_lock = threading.Lock()

# 股票数据缓存文件路径
STOCK_DATA_FILE = 'stock_data.csv'

def get_db_connection():
    """创建数据库连接"""
    return pymysql.connect(
        host=DB_HOST,
        port=DB_PORT,
        user=DB_USER,
        password=DB_PASSWORD,
        database=DB_NAME,
        charset='utf8mb4',
        cursorclass=pymysql.cursors.DictCursor
    )

def init_db():
    """初始化数据库表结构（如果不存在）"""
    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            # 创建表（如果不存在）
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS `xdb_ai` (
                    `stock_id` VARCHAR(10) NOT NULL,
                    `stock_name` VARCHAR(50) DEFAULT '',
                    `financial_analyzer` TEXT,
                    `financial_analyzer_tm` DATETIME DEFAULT NULL,
                    `technical_analyzer` TEXT,
                    `technical_analyzer_tm` DATETIME DEFAULT NULL,
                    PRIMARY KEY (`stock_id`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
            """)
            
            # 创建用户日志表
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS `user_log` (
                    `id` INT(11) NOT NULL AUTO_INCREMENT,
                    `user` VARCHAR(255) DEFAULT '',
                    `tm` DATETIME DEFAULT NULL,
                    `stock_id` VARCHAR(10) DEFAULT NULL,
                    `stock_name` VARCHAR(50) DEFAULT '',
                    `method` VARCHAR(50) DEFAULT '',
                    PRIMARY KEY (`id`),
                    INDEX `idx_user_tm` (`user`, `tm`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
            """)
        connection.commit()
        logger.info("数据库表初始化成功")
    except Exception as e:
        logger.error(f"数据库初始化失败: {str(e)}")
    finally:
        if connection:
            connection.close()

def save_to_db(stock_code, stock_name, analyzer_type, result):
    """将分析结果保存到数据库"""
    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            now = datetime.now()
            
            # 检查记录是否存在
            cursor.execute(
                "SELECT * FROM `xdb_ai` WHERE `stock_id` = %s",
                (stock_code,)
            )
            existing = cursor.fetchone()
            
            if existing:
                # 更新现有记录
                if analyzer_type == 'financial':
                    cursor.execute("""
                        UPDATE `xdb_ai` 
                        SET `financial_analyzer` = %s, `financial_analyzer_tm` = %s 
                        WHERE `stock_id` = %s
                    """, (json.dumps(result), now, stock_code))
                else:  # technical
                    cursor.execute("""
                        UPDATE `xdb_ai` 
                        SET `technical_analyzer` = %s, `technical_analyzer_tm` = %s 
                        WHERE `stock_id` = %s
                    """, (json.dumps(result), now, stock_code))
            else:
                # 插入新记录
                if analyzer_type == 'financial':
                    cursor.execute("""
                        INSERT INTO `xdb_ai` 
                        (`stock_id`, `stock_name`, `financial_analyzer`, `financial_analyzer_tm`) 
                        VALUES (%s, %s, %s, %s)
                    """, (stock_code, stock_name, json.dumps(result), now))
                else:  # technical
                    cursor.execute("""
                        INSERT INTO `xdb_ai` 
                        (`stock_id`, `stock_name`, `technical_analyzer`, `technical_analyzer_tm`) 
                        VALUES (%s, %s, %s, %s)
                    """, (stock_code, stock_name, json.dumps(result), now))
        connection.commit()
        logger.info(f"成功保存{analyzer_type}分析结果到数据库: {stock_code}")
        return True
    except Exception as e:
        logger.error(f"保存{analyzer_type}分析结果到数据库失败: {str(e)}")
        return False
    finally:
        if connection:
            connection.close()

def get_from_db(stock_code, analyzer_type):
    """从数据库获取分析结果"""
    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            cursor.execute(
                "SELECT * FROM `xdb_ai` WHERE `stock_id` = %s",
                (stock_code,)
            )
            result = cursor.fetchone()
            
            if not result:
                return None
                
            # 检查缓存是否有效
            now = datetime.now()
            if analyzer_type == 'financial':
                if result.get('financial_analyzer_tm'):
                    cache_time = result['financial_analyzer_tm']
                    if (now - cache_time).total_seconds() < 86400:  # 24小时有效期
                        return json.loads(result['financial_analyzer'])
            else:  # technical
                if result.get('technical_analyzer_tm'):
                    cache_time = result['technical_analyzer_tm']
                    if (now - cache_time).total_seconds() < 43200:  # 12小时有效期
                        return json.loads(result['technical_analyzer'])
        return None
    except Exception as e:
        logger.error(f"从数据库获取{analyzer_type}分析结果失败: {str(e)}")
        return None
    finally:
        if connection:
            connection.close()

def log_user_request(user, stock_id, method):
    """记录用户请求到数据库"""
    try:
        # 获取股票名称
        stock_name = ""
        with stock_lock:
            for stock in all_stocks:
                if stock['code'] == stock_id:
                    stock_name = stock['name']
                    break
        
        # 插入日志记录
        connection = get_db_connection()
        with connection.cursor() as cursor:
            cursor.execute("""
                INSERT INTO `user_log` 
                (`user`, `tm`, `stock_id`, `stock_name`, `method`)
                VALUES (%s, %s, %s, %s, %s)
            """, (user, datetime.now(), stock_id, stock_name, method))
        connection.commit()
        logger.info(f"记录用户请求: {user} - {method} - {stock_id} ({stock_name})")
        return True
    except Exception as e:
        logger.error(f"记录用户请求失败: {str(e)}")
        return False
    finally:
        if connection:
            connection.close()

def load_stock_data():
    """加载股票数据到内存"""
    stocks = []
    if os.path.exists(STOCK_DATA_FILE):
        with open(STOCK_DATA_FILE, 'r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            for row in reader:
                stocks.append({
                    'code': row['code'],
                    'name': row['name']
                })
    return stocks

def fetch_and_save_stock_data():
    """从akshare获取股票数据并保存到文件"""
    try:
        logger.info("开始获取A股股票列表数据...")
        # 获取A股股票代码和名称
        df = ak.stock_info_a_code_name()
        
        # 转换为字典列表
        stocks = []
        for _, row in df.iterrows():
            stocks.append({
                'code': row['code'],
                'name': row['name']
            })
        
        # 保存到CSV文件
        with open(STOCK_DATA_FILE, 'w', encoding='utf-8', newline='') as f:
            fieldnames = ['code', 'name']
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            writer.writerows(stocks)
        
        logger.info(f"成功保存{len(stocks)}条股票数据到{STOCK_DATA_FILE}")
        return stocks
    except Exception as e:
        logger.error(f"获取股票数据失败: {str(e)}")
        # 尝试加载现有数据
        return load_stock_data()

# 全局股票列表
all_stocks = []
stock_lock = threading.Lock()

def update_stock_data_task():
    """定时更新股票数据的任务"""
    global all_stocks
    while True:
        try:
            # 每天凌晨3点更新
            now = datetime.now()
            next_run = now.replace(hour=3, minute=0, second=0, microsecond=0)
            if now.hour >= 3:
                next_run += timedelta(days=1)
            
            wait_seconds = (next_run - now).total_seconds()
            logger.info(f"下次股票数据更新将在: {next_run} ({wait_seconds:.0f}秒后)")
            time.sleep(wait_seconds)
            
            with stock_lock:
                logger.info("开始定时更新股票数据...")
                all_stocks = fetch_and_save_stock_data()
                logger.info(f"股票数据更新完成，共{len(all_stocks)}条记录")
        except Exception as e:
            logger.error(f"股票数据更新任务出错: {str(e)}")
            time.sleep(3600)  # 出错后等待1小时再重试

@app.route('/search_stock', methods=['POST'])
def search_stock():
    """根据部分名称搜索股票（POST方法）"""
    # 获取请求参数
    data = request.json
    keyword = data.get('keyword', '')
    
    if not keyword:
        logger.warning("搜索股票接口收到空关键词请求")
        return jsonify({'error': '请输入搜索关键词'}), 400
    
    logger.info(f"搜索股票: {keyword}")
    
    with stock_lock:
        # 复制当前股票列表避免处理时被更新
        current_stocks = all_stocks.copy()
    
    results = []
    for stock in current_stocks:
        # 支持同时搜索代码和名称
        if keyword in stock['name'] or keyword in stock['code']:
            results.append({
                'code': stock['code'],
                'name': stock['name']
            })
            if len(results) >= 10:  # 最多返回10条结果
                break
    
    logger.info(f"找到{len(results)}条匹配结果")
    return jsonify(results)

# 应用启动时初始化股票数据和数据库
with stock_lock:
    if os.path.exists(STOCK_DATA_FILE):
        # 检查文件更新时间，如果超过1天则重新获取
        file_time = datetime.fromtimestamp(os.path.getmtime(STOCK_DATA_FILE))
        if (datetime.now() - file_time).days > 1:
            logger.info("股票数据文件过期，重新获取...")
            all_stocks = fetch_and_save_stock_data()
        else:
            logger.info("从文件加载股票数据...")
            all_stocks = load_stock_data()
    else:
        logger.info("首次获取股票数据...")
        all_stocks = fetch_and_save_stock_data()

logger.info(f"共加载{len(all_stocks)}条股票数据")

# 初始化数据库
init_db()

# 启动股票数据更新线程
update_thread = threading.Thread(target=update_stock_data_task, daemon=True)
update_thread.start()
logger.info("股票数据自动更新线程已启动")

def init_financial_analyzer():
    global financial_analyzer
    with analyzer_lock:
        if financial_analyzer is None:
            logger.info("初始化股票财务分析器...")
            financial_analyzer = StockFinancialAnalyzer()
            logger.info("股票财务分析器初始化完成")

def init_technical_analyzer():
    global technical_analyzer
    with analyzer_lock:
        if technical_analyzer is None:
            logger.info("初始化股票技术分析器...")
            technical_analyzer = StockTechnicalAnalyzer()
            logger.info("股票技术分析器初始化完成")

def generate_task_id(stock_input, analyzer_type):
    """生成唯一的任务ID"""
    unique_str = f"{stock_input}-{analyzer_type}-{time.time()}"
    return hashlib.sha256(unique_str.encode()).hexdigest()[:16]

def perform_financial_analysis(task_id, stock_input):
    """后台执行财务分析任务的函数"""
    try:
        logger.info(f"开始处理财务分析任务 {task_id} (股票: {stock_input})")
        start_time = time.time()
        
        # 确保分析器已初始化
        init_financial_analyzer()
        
        # 获取并分析财务数据
        logger.info(f"任务 {task_id} - 开始财务数据分析...")
        analysis_result = financial_analyzer.analyze_financial_data(stock_input)
        logger.info(f"任务 {task_id} - 财务数据分析完成，结果长度: {len(analysis_result)}")
        
        # 获取股票信息（用于存储名称）
        stock_info = fetch_stock_info(stock_input)
        stock_name = stock_info.get('name', '') if stock_info else ''
        
        # 保存结果到数据库
        save_to_db(stock_input, stock_name, 'financial', analysis_result)
        
        # 更新任务缓存
        with financial_cache_lock:
            financial_task_cache[task_id] = {
                'status': 'success',
                'result': analysis_result,
                'timestamp': datetime.now().isoformat()
            }
            
        elapsed_time = time.time() - start_time
        logger.info(f"财务分析任务 {task_id} 处理成功! 耗时: {elapsed_time:.2f}秒")
        
    except Exception as e:
        logger.error(f"财务分析任务 {task_id} 处理失败: {str(e)}", exc_info=True)
        with financial_cache_lock:
            financial_task_cache[task_id] = {
                'status': 'failed',
                'error': str(e),
                'timestamp': datetime.now().isoformat()
            }

def perform_technical_analysis(task_id, stock_input):
    """后台执行技术分析任务的函数"""
    try:
        logger.info(f"开始处理技术分析任务 {task_id} (股票: {stock_input})")
        start_time = time.time()
        
        # 确保分析器已初始化
        init_technical_analyzer()
        
        # 执行技术分析
        logger.info(f"任务 {task_id} - 开始技术数据分析...")
        analysis_result = technical_analyzer.analyze_stock(stock_input)
        logger.info(f"任务 {task_id} - 技术数据分析完成，结果长度: {len(analysis_result)}")
        
        # 获取股票信息（用于存储名称）
        stock_info = fetch_stock_info(stock_input)
        stock_name = stock_info.get('name', '') if stock_info else ''
        
        # 保存结果到数据库
        save_to_db(stock_input, stock_name, 'technical', analysis_result)
        
        # 更新任务缓存
        with technical_cache_lock:
            technical_task_cache[task_id] = {
                'status': 'success',
                'result': analysis_result,
                'timestamp': datetime.now().isoformat()
            }
            
        elapsed_time = time.time() - start_time
        logger.info(f"技术分析任务 {task_id} 处理成功! 耗时: {elapsed_time:.2f}秒")
        
    except Exception as e:
        logger.error(f"技术分析任务 {task_id} 处理失败: {str(e)}", exc_info=True)
        with technical_cache_lock:
            technical_task_cache[task_id] = {
                'status': 'failed',
                'error': str(e),
                'timestamp': datetime.now().isoformat()
            }

@app.route('/analyze_stock', methods=['POST'])
def analyze_stock():
    """提交财务分析任务的接口"""
    logger.info("收到股票财务分析请求")
    
    # 获取请求参数
    data = request.json
    user = data.get('user_id', 'unknown')  # 从POST字段获取user_id
    stock_input = data.get('stock_input')
    
    if not user:
        logger.warning("用户ID为空，使用'unknown'")
        user = 'unknown'
    
    logger.info(f"请求参数 - 用户: {user}, 股票代码: {stock_input}")
    t_stock_info = fetch_stock_info(stock_input)
    
    # 基础验证
    if not stock_input or t_stock_info is None or (len(stock_input) != 6 and not stock_input.isdigit()):
        logger.warning(f"无效股票输入: {stock_input}")
        return jsonify({'error': '无效的股票输入，请输入6位纯数字代码或股票名称'}), 400
    
    # 记录用户请求
    log_user_request(user, stock_input, 'financial_analysis')
    
    # 生成唯一任务ID
    task_id = generate_task_id(stock_input, "financial")
    logger.info(f"生成财务分析任务ID: {task_id}")
    
    # 检查数据库缓存
    cached_result = get_from_db(stock_input, 'financial')
    if cached_result:
        logger.info(f"任务 {task_id} - 数据库缓存命中!")
        
        # 更新任务缓存
        with financial_cache_lock:
            financial_task_cache[task_id] = {
                'status': 'success',
                'result': cached_result,
                'timestamp': datetime.now().isoformat()
            }
        
        return jsonify({
            'task_id': task_id,
            'status': 'pending',
            'message': '分析任务已提交，请稍后查询结果',
            'query_endpoint': f'/query_financial_analysis/{task_id}',
            'cached': True
        }), 202
    
    # 检查是否已有相同任务
    with financial_cache_lock:
        if task_id in financial_task_cache:
            existing_task = financial_task_cache[task_id]
            logger.info(f"任务 {task_id} 已存在，状态: {existing_task['status']}")
            
            if existing_task['status'] == 'pending':
                return jsonify({
                    'task_id': task_id,
                    'status': 'pending',
                    'message': '分析任务已提交，正在处理中',
                    'query_endpoint': f'/query_financial_analysis/{task_id}'
                }), 202
            else:
                # 重新生成任务ID
                new_task_id = generate_task_id(stock_input + str(time.time()), "financial")
                logger.info(f"任务 {task_id} 已完成或失败，创建新任务ID: {new_task_id}")
                task_id = new_task_id
    
    # 创建新任务
    with financial_cache_lock:
        financial_task_cache[task_id] = {
            'status': 'pending',
            'created_at': datetime.now().isoformat(),
            'stock_input': stock_input
        }
    
    logger.info(f"创建新财务分析任务 {task_id}，启动后台线程...")
    
    # 启动后台线程执行分析任务
    threading.Thread(
        target=perform_financial_analysis,
        args=(task_id, stock_input),
        daemon=True
    ).start()
    
    logger.info(f"财务分析任务 {task_id} 已提交后台处理")
    
    return jsonify({
        'task_id': task_id,
        'status': 'pending',
        'message': '分析任务已提交，请稍后查询结果',
        'query_endpoint': f'/query_financial_analysis/{task_id}'
    }), 202

@app.route('/short_term_analysis', methods=['POST'])
def short_term_analysis():
    """提交短期技术分析任务的接口"""
    logger.info("收到股票技术分析请求")
    
    # 获取请求参数
    data = request.json
    user = data.get('user_id', 'unknown')  # 从POST字段获取user_id
    stock_input = data.get('stock_input')
    
    if not user:
        logger.warning("用户ID为空，使用'unknown'")
        user = 'unknown'
    
    logger.info(f"请求参数 - 用户: {user}, 股票代码: {stock_input}")
    # 尝试获取股票信息
    t_stock_info = fetch_stock_info(stock_input)
    # 基础验证
    if not stock_input or t_stock_info is None or (len(stock_input) != 6 and not stock_input.isdigit()):
        logger.warning(f"无效股票输入: {stock_input}")
        return jsonify({'error': '无效的股票输入，请输入正确的6位纯数字代码'}), 400
    
    # 记录用户请求
    log_user_request(user, stock_input, 'technical_analysis')
    
    # 生成唯一任务ID
    task_id = generate_task_id(stock_input, "technical")
    logger.info(f"生成技术分析任务ID: {task_id}")
    
    # 检查数据库缓存
    cached_result = get_from_db(stock_input, 'technical')
    if cached_result:
        logger.info(f"技术分析任务 {task_id} - 数据库缓存命中!")
        
        # 更新任务缓存
        with technical_cache_lock:
            technical_task_cache[task_id] = {
                'status': 'success',
                'result': cached_result,
                'timestamp': datetime.now().isoformat()
            }
        
        return jsonify({
            'task_id': task_id,
            'status': 'pending',
            'message': '技术分析任务已提交，请稍后查询结果',
            'query_endpoint': f'/query_technical_analysis/{task_id}',
            'cached': True
        }), 202
    
    # 检查是否已有相同任务
    with technical_cache_lock:
        if task_id in technical_task_cache:
            existing_task = technical_task_cache[task_id]
            logger.info(f"技术分析任务 {task_id} 已存在，状态: {existing_task['status']}")
            
            if existing_task['status'] == 'pending':
                return jsonify({
                    'task_id': task_id,
                    'status': 'pending',
                    'message': '技术分析任务已提交，正在处理中',
                    'query_endpoint': f'/query_technical_analysis/{task_id}'
                }), 202
            else:
                # 重新生成任务ID
                new_task_id = generate_task_id(stock_input + str(time.time()), "technical")
                logger.info(f"技术分析任务 {task_id} 已完成或失败，创建新任务ID: {new_task_id}")
                task_id = new_task_id
    
    # 创建新任务
    with technical_cache_lock:
        technical_task_cache[task_id] = {
            'status': 'pending',
            'created_at': datetime.now().isoformat(),
            'stock_input': stock_input
        }
    
    logger.info(f"创建新技术分析任务 {task_id}，启动后台线程...")
    
    # 启动后台线程执行分析任务
    threading.Thread(
        target=perform_technical_analysis,
        args=(task_id, stock_input),
        daemon=True
    ).start()
    
    logger.info(f"技术分析任务 {task_id} 已提交后台处理")
    
    return jsonify({
        'task_id': task_id,
        'status': 'pending',
        'message': '技术分析任务已提交，请稍后查询结果',
        'query_endpoint': f'/query_technical_analysis/{task_id}'
    }), 202

@app.route('/query_financial_analysis/<task_id>', methods=['GET'])
def query_financial_analysis(task_id):
    """查询财务分析结果的接口"""
    logger.info(f"查询财务分析任务状态: {task_id}")
    
    with financial_cache_lock:
        task_data = financial_task_cache.get(task_id)
    
    if not task_data:
        # 尝试从数据库恢复结果（如果应用重启）
        logger.info(f"任务ID {task_id} 不在内存中，尝试从数据库恢复")
        stock_input = None
        
        # 尝试从内存缓存查找任务对应的股票代码
        # 实际应用中可能需要更好的恢复机制，这里简化处理
        for tid, data in financial_task_cache.items():
            if tid == task_id:
                stock_input = data.get('stock_input')
                break
        
        if stock_input:
            logger.info(f"找到任务 {task_id} 对应的股票代码: {stock_input}")
            cached_result = get_from_db(stock_input, 'financial')
            if cached_result:
                logger.info(f"从数据库恢复任务 {task_id} 结果")
                financial_task_cache[task_id] = {
                    'status': 'success',
                    'result': cached_result,
                    'timestamp': datetime.now().isoformat()
                }
                task_data = financial_task_cache.get(task_id)
    
    if not task_data:
        logger.warning(f"财务分析任务ID不存在: {task_id}")
        return jsonify({
            'status': 'not_found',
            'error': '任务ID不存在'
        }), 404
    
    if task_data['status'] == 'pending':
        logger.info(f"任务 {task_id} 仍在处理中")
        return jsonify({
            'task_id': task_id,
            'status': 'pending',
            'message': '分析仍在进行中，请稍后再试',
            'retry_after': 5
        }), 202
    
    if task_data['status'] == 'success':
        logger.info(f"任务 {task_id} 查询成功")
        return jsonify({
            'task_id': task_id,
            'status': 'success',
            'result': task_data['result'],
            'generated_at': task_data['timestamp']
        }), 200
    
    if task_data['status'] == 'failed':
        logger.error(f"任务 {task_id} 查询失败: {task_data['error']}")
        return jsonify({
            'task_id': task_id,
            'status': 'failed',
            'error': task_data['error'],
            'failed_at': task_data['timestamp']
        }), 500

@app.route('/query_technical_analysis/<task_id>', methods=['GET'])
def query_technical_analysis(task_id):
    """查询技术分析结果的接口"""
    logger.info(f"查询技术分析任务状态: {task_id}")
    
    with technical_cache_lock:
        task_data = technical_task_cache.get(task_id)
    
    if not task_data:
        # 尝试从数据库恢复结果（如果应用重启）
        logger.info(f"任务ID {task_id} 不在内存中，尝试从数据库恢复")
        stock_input = None
        
        # 尝试从内存缓存查找任务对应的股票代码
        for tid, data in technical_task_cache.items():
            if tid == task_id:
                stock_input = data.get('stock_input')
                break
        
        if stock_input:
            logger.info(f"找到任务 {task_id} 对应的股票代码: {stock_input}")
            cached_result = get_from_db(stock_input, 'technical')
            if cached_result:
                logger.info(f"从数据库恢复任务 {task_id} 结果")
                technical_task_cache[task_id] = {
                    'status': 'success',
                    'result': cached_result,
                    'timestamp': datetime.now().isoformat()
                }
                task_data = technical_task_cache.get(task_id)
    
    if not task_data:
        logger.warning(f"技术分析任务ID不存在: {task_id}")
        return jsonify({
            'status': 'not_found',
            'error': '任务ID不存在'
        }), 404
    
    if task_data['status'] == 'pending':
        logger.info(f"技术分析任务 {task_id} 仍在处理中")
        return jsonify({
            'task_id': task_id,
            'status': 'pending',
            'message': '技术分析仍在进行中，请稍后再试',
            'retry_after': 5
        }), 202
    
    if task_data['status'] == 'success':
        logger.info(f"技术分析任务 {task_id} 查询成功")
        return jsonify({
            'task_id': task_id,
            'status': 'success',
            'result': task_data['result'],
            'generated_at': task_data['timestamp']
        }), 200
    
    if task_data['status'] == 'failed':
        logger.error(f"技术分析任务 {task_id} 查询失败: {task_data['error']}")
        return jsonify({
            'task_id': task_id,
            'status': 'failed',
            'error': task_data['error'],
            'failed_at': task_data['timestamp']
        }), 500

# 定时清理数据库缓存
def cleanup_db_cache():
    """定期清理过期的数据库缓存"""
    logger.info("启动数据库缓存清理线程")
    
    while True:
        try:
            time.sleep(3600)  # 每小时清理一次
            current_time = datetime.now()
            logger.info("开始清理过期数据库缓存...")
            
            updated_financial = 0
            updated_technical = 0
            
            try:
                connection = get_db_connection()
                with connection.cursor() as cursor:
                    # 清理过期财务分析缓存（24小时）
                    cursor.execute(
                        "UPDATE `xdb_ai` SET `financial_analyzer` = NULL, `financial_analyzer_tm` = NULL "
                        "WHERE `financial_analyzer_tm` < %s",
                        (current_time - timedelta(hours=24),))
                    updated_financial = cursor.rowcount
                    
                    # 清理过期技术分析缓存（12小时）
                    cursor.execute(
                        "UPDATE `xdb_ai` SET `technical_analyzer` = NULL, `technical_analyzer_tm` = NULL "
                        "WHERE `technical_analyzer_tm` < %s",
                        (current_time - timedelta(hours=12),))
                    updated_technical = cursor.rowcount
                
                connection.commit()
                logger.info(
                    f"数据库缓存清理完成! "
                    f"财务缓存: {updated_financial}条, 技术缓存: {updated_technical}条"
                )
            except Exception as e:
                logger.error(f"清理数据库缓存出错: {str(e)}")
            finally:
                if connection:
                    connection.close()
            
        except Exception as e:
            logger.error(f"缓存清理线程出错: {str(e)}", exc_info=True)
            time.sleep(60)  # 出错后等待1分钟再重试
# 启动清理线程
cleanup_thread = threading.Thread(target=cleanup_db_cache, daemon=True)
cleanup_thread.start()
logger.info("数据库缓存清理线程已启动")

@app.route('/recent_stocks', methods=['POST'])
def get_recent_stocks():
    """获取用户最近查询的3只股票（去重）"""
    # 获取用户信息
    data = request.json
    user = data.get('user_id', 'unknown')  # 从POST字段获取user_id
    
    if not user:
        logger.warning("用户ID为空，使用'unknown'")
        user = 'unknown'
    
    logger.info(f"获取用户最近查询股票: {user}")
    
    try:
        connection = get_db_connection()
        with connection.cursor() as cursor:
            # 查询用户最近3条不重复的股票记录
            cursor.execute("""
                SELECT DISTINCT stock_id, stock_name
                FROM user_log
                WHERE user = %s
                ORDER BY tm DESC
                LIMIT 3
            """, (user,))
            
            results = cursor.fetchall()
            
            # 转换为所需格式
            stocks = []
            for row in results:
                stocks.append({
                    'stock_id': row['stock_id'],
                    'stock_name': row['stock_name']
                })
            
            logger.info(f"找到用户 {user} 的 {len(stocks)} 条最近查询记录")
            return jsonify(stocks), 200
    except Exception as e:
        logger.error(f"查询用户最近股票失败: {str(e)}")
        return jsonify({'error': '查询失败，请稍后再试'}), 500
    finally:
        if connection:
            connection.close()

@app.route('/')
def index():
    logger.info("访问首页")
    return 'hello world'

@app.route('/index_detail')
def index_detail():
    logger.info("访问首页详情")
    return '{"title":"筱竹豆包AI", "search_button":"🔍基本面分析", "technical_button":"🔍短线分析"}';

@app.route('/api/count', methods=['POST'])
def count():
    """
    :return:计数结果/清除结果
    """
    logger.info("访问计数器API (POST)")
    
    # 获取请求体参数
    params = request.get_json()

    # 检查action参数
    if 'action' not in params:
        logger.warning("计数器API缺少action参数")
        return make_err_response('缺少action参数')

    # 按照不同的action的值，进行不同的操作
    action = params['action']
    logger.info(f"计数器操作: {action}")

    # 执行自增操作
    if action == 'inc':
        counter = query_counterbyid(1)
        if counter is None:
            logger.info("创建新计数器")
            counter = Counters()
            counter.id = 1
            counter.count = 1
            counter.created_at = datetime.now()
            counter.updated_at = datetime.now()
            insert_counter(counter)
        else:
            logger.info(f"增加计数器值: {counter.count} -> {counter.count + 1}")
            counter.id = 1
            counter.count += 1
            counter.updated_at = datetime.now()
            update_counterbyid(counter)
        return make_succ_response(counter.count)

    # 执行清0操作
    elif action == 'clear':
        logger.info("清除计数器")
        delete_counterbyid(1)
        return make_succ_empty_response()

    # action参数错误
    else:
        logger.warning(f"无效的计数器操作: {action}")
        return make_err_response('action参数错误')


@app.route('/api/count', methods=['GET'])
def get_count():
    """
    :return: 计数的值
    """
    logger.info("访问计数器API (GET)")
    counter = Counters.query.filter(Counters.id == 1).first()
    return make_succ_response(0) if counter is None else make_succ_response(counter.count)

@app.route('/get_stock_detail', methods=['POST'])
def get_stock_detail():
    """获取股票详细信息接口"""
    logger.info("收到获取股票详情请求")
    
    # 获取请求参数
    data = request.json
    stock_input = data.get('stock_input')
    
    # 基础验证
    if not stock_input or (len(stock_input) != 6 and not stock_input.isdigit()):
        logger.warning(f"无效股票输入: {stock_input}")
        return jsonify({'error': '无效的股票输入，请输入6位纯数字代码'}), 400
    
    # 尝试获取股票信息
    stock_info = fetch_stock_info(stock_input)
    
    if stock_info is None:
        logger.error(f"无法获取股票信息: {stock_input}")
        return jsonify({
            'error': '获取股票信息失败，请检查股票代码是否正确或稍后重试'
        }), 500
    
    return jsonify(stock_info), 200
